package order

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"time"

	"mall/common/globalkey"
	"mall/common/jwt"
	"mall/common/moneyx"
	"mall/common/mqueuex"
	"mall/common/resultx"
	"mall/common/utils/pointy"
	"mall/service/forum/api/internal/logic/util"
	"mall/service/forum/api/internal/svc"
	"mall/service/forum/api/internal/types"
	"mall/service/order/rpc/orderclient"
	"mall/service/setting/rpc/settingclient"
	"mall/service/user/rpc/userclient"

	"github.com/zeromicro/go-zero/core/logx"
)

type ConfirmOrderLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewConfirmOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ConfirmOrderLogic {
	return &ConfirmOrderLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *ConfirmOrderLogic) ConfirmOrder(
	req *types.ConfirmOrderReq,
	headers *[]*types.Header,
) (resp *types.ConfirmOrderResp, err error) {
	if req.Id == nil || *req.Id == 0 {
		return nil, resultx.NewErrCode(resultx.ORDER_ID_REQUIRED)
	}

	userId := jwt.GetUserId(l.ctx)
	if userId == 0 {
		return nil, resultx.NewErrCode(resultx.TOKEN_EXPIRE_ERROR)
	}

	preload := "order:Id,ActualAmount"
	var filters []string
	filters = append(filters, "Id,equalTo:"+strconv.FormatInt(int64(*req.Id), 10))
	filters = append(filters, "UserId,equalTo:"+strconv.FormatInt(int64(userId), 10))
	filters = append(filters, "TradeState,equalTo:"+strconv.FormatInt(int64(globalkey.OrderTradeStateShipped), 10))
	var platformId = globalkey.ThirdPartyPlatformWechatMini

	res, err := l.svcCtx.OrderRpc.GetOrderById(l.ctx, &orderclient.BaseIdReq{
		Preload:    pointy.GetPointer(preload),
		Filter:     pointy.GetPointer(strings.Join(filters, ";")),
		VisitorId:  pointy.GetPointer(userId),
		PlatformId: pointy.GetPointer(platformId),
	})
	if err != nil {
		logx.Errorw("ConfirmOrder GetOrderById err", logx.Field("detail", err.Error()))
		return nil, resultx.NewErrCode(resultx.ORDER_PARAM_INVALID)
	}

	if res == nil || res.Id == nil || *res.Id == 0 {
		return nil, resultx.NewErrCode(resultx.ORDER_PARAM_INVALID)
	}

	tradeState := pointy.GetPointer(globalkey.OrderTradeStateConfirmed)
	_, err = l.svcCtx.OrderRpc.UpdateTradeState(l.ctx, &orderclient.UpdateTradeStateReq{
		Id:         res.Id,
		TradeState: tradeState,
	})
	if err != nil {
		logx.Errorw("ConfirmOrder UpdateTradeState err", logx.Field("detail", err.Error()))
		return nil, err
	}
	option := util.GetOptionByStatus(tradeState)

	//购物返利
	if res.ActualAmount != nil && len(strings.TrimSpace(*res.ActualAmount)) > 0 {
		//转元	195000 ==> 195
		//实付金额:积分  ==>	1:1
		actualAmount, err := strconv.ParseUint(*res.ActualAmount, 10, 64)
		if err != nil {
			return nil, err
		}
		points := moneyx.FormatGem(int64(actualAmount))
		err = l.pointsDistributeLogic(userId, *req.TaskId, *req.Id, points, globalkey.UserAssetSourceTypeReward)
		if err != nil {
			logx.Errorw(fmt.Sprintf("ConfirmOrder  pointsDistributeLogic error:%+v", err))
		}
	}
	//是否触发积分分发逻辑-积分任务
	if req.TaskId != nil && *req.TaskId > 0 {
		//查询任务频率
		task, err := l.svcCtx.SettingRpc.GetIntegralTaskById(l.ctx, &settingclient.IntegralTaskDetailReq{
			Id: req.TaskId,
		})
		if err != nil {
			logx.Errorw("ConfirmOrder CreateFileLog err", logx.Field("detail", err.Error()))
		}
		if task.Frequency != nil {
			if *task.Frequency == 0 {
				//Frequency == 0  无上限
				err = l.pointsDistributeLogic(userId, *req.TaskId, *req.Id, "0", globalkey.UserAssetSourceTypeTask)
				if err != nil {
					logx.Errorw(fmt.Sprintf("ConfirmOrder  pointsDistributeLogic error:%+v", err))
				}
			} else {
				//有上限
				//查询用户当天该任务是否超出次数
				now := time.Now()
				// 获取当天的起始时间（午夜）
				startOfDay := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
				// 获取当天的终止时间（午夜前的最后一秒）
				endOfDay := startOfDay.AddDate(0, 0, 1).Add(-time.Second)
				var filters []string
				filters = append(filters, "UserId,equalTo:"+strconv.FormatInt(int64(userId), 10))
				filters = append(filters, "TaskId,equalTo:"+strconv.FormatInt(int64(*req.TaskId), 10))
				filters = append(filters, "Status,equalTo:"+strconv.FormatInt(int64(globalkey.StatusEnabled), 10))
				filters = append(filters, "UpdatedAt,moreThanOrEqualTo:"+startOfDay.Format("2006-01-02 15:04:05"))
				filters = append(filters, "UpdatedAt,lessThan:"+endOfDay.Format("2006-01-02 15:04:05"))
				userTaskLog, err := l.svcCtx.UserRpc.GetIntegralTaskLogList(l.ctx, &userclient.BaseListReq{
					Filter: pointy.GetPointer(strings.Join(filters, ";")),
				})
				if err != nil {
					logx.Errorw("ConfirmOrder CreateFileLog err", logx.Field("detail", err.Error()))
				}
				//userTaskLog.Total < uint64(*task.Frequency)  已完成次数 < 每日限制次数
				if userTaskLog != nil && userTaskLog.Total < uint64(*task.Frequency) {
					err = l.pointsDistributeLogic(userId, *req.TaskId, *req.Id, "0", globalkey.UserAssetSourceTypeTask)
					if err != nil {
						logx.Errorw(fmt.Sprintf("ConfirmOrder  pointsDistributeLogic error:%+v", err))
					}
				}
			}
		}
	}

	return &types.ConfirmOrderResp{
		Option: &types.TradeInfoFragment{
			TradeState:     tradeState,
			TradeStateText: util.GetTradeStateText(tradeState),
			CanCancel:      option.CanCancel,
			CanPay:         option.CanPay,
			CanRefund:      option.CanRefund,
			CanRemind:      option.CanRemind,
			CanTrack:       option.CanTrack,
			CanConfirm:     option.CanConfirm,
			CanInvoice:     option.CanInvoice,
			CanRemove:      option.CanRemove,
		},
	}, nil
}

// 发放积分
func (l *ConfirmOrderLogic) pointsDistributeLogic(uid, tid, orderId uint64, points string, sType uint32) error {
	var m = mqueuex.DistributePointsMessage{
		UserId:   pointy.GetPointer(uid),
		SourceId: pointy.GetPointer(orderId),
	}
	if sType == globalkey.UserAssetSourceTypeTask && tid > 0 {
		// 积分任务
		m.TaskId = pointy.GetPointer(tid)
		m.SourceType = pointy.GetPointer(sType)
	} else if sType == globalkey.UserAssetSourceTypeReward && len(points) > 0 {
		// 消费返利
		m.Points = pointy.GetPointer(points)
		m.SourceType = pointy.GetPointer(sType)
	}
	body, err := json.Marshal(m)
	if err != nil {
		logx.Errorw(fmt.Sprintf("kq DistributePointsClient message json.Marshal error:%+v", err))
		return errors.New(fmt.Sprintf("kq DistributePointsClient message json.Marshal error:%+v", err))
	}

	return l.svcCtx.KqDistributePointsClient.Push(string(body))
}
